
package chui;

import java.io.IOException;
import java.util.ArrayList;

import model.ZoneRelay;
import util.SimpleConfig;
import edu.cmu.cs.Termio;

/**
 * [Work in process]
 * 
 * @author rpitts@gmu.edu
 *
 */
public class ZoneConsole {


	public static void main(String[] args) {

		ZoneRelay zone = null;
		String zoneName = "";
		//String remoteZones = "";
		int zoneSide = 0;
		int windowSize = 0;
		int localPort = 0;
		int nodesStarted = 0;
		int mean = 6;
		
		Termio input = new Termio();		// Termio IO Object
		boolean Done = false;				// Main loop flag
		String Option = null;				// Menu choice from user
		//boolean Error = false;				// Error flag
		ZoneMonitor monitor = null;			// The zone system monitor
		SimpleConfig config = null;

		int intOption = 0;
		
		String propertiesFile = args[0];
		
		String basePath = ""; 
		
		ArrayList<String> hydraNodes = null;
		boolean runDistributed = false;
		
		try {
			config = new SimpleConfig(propertiesFile);
			zoneName = config.getProperty("zoneName");
			zoneSide = config.getIntProperty("zoneSide");
			localPort = config.getIntProperty("localPort");
			basePath = config.getProperty("basePath");
			windowSize = config.getIntProperty("windowSize");
			mean = config.getIntProperty("mean");
			
			
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		
		System.out.println("Starting Zone: " + zoneName + " in base path: " + basePath);
		zone = new ZoneRelay(zoneName, zoneSide, windowSize, localPort);

		addRemoteZones(config, zone);
		hydraNodes = addRunNodes(config);
		runDistributed = (hydraNodes.size() > 0);
		if (runDistributed) { 
			for (int i = 0; i < hydraNodes.size(); i++) {
				System.out.println(hydraNodes.get(i));
			}
		} else {
			System.out.println("Run Locally");
		}

		
		try {
			monitor = new ZoneMonitor(zone, basePath, mean);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		while (!Done)
		{
			// Here, the main thread continues and provides the main menu

			printConsoleMenu();

			Option = input.KeyboardReadString();
			
			if ( Option.equalsIgnoreCase( "M" ) )
			{
	
				System.out.println( "\nSimulate MedVac Request." );
				monitor.sendMedVac(null);

			} // if
			
			else if ( Option.equalsIgnoreCase( "C" ) )
			{  
				Runtime runTime = Runtime.getRuntime();
				System.out.println( "\nMemory: " 
						            + "Free: " + runTime.freeMemory() + " " 
						            + "Total: " + runTime.totalMemory() + " "
						            + "Max: " + runTime.maxMemory());
				
				System.out.println(runTime.toString());
			} // if
			
			else if ( Option.equalsIgnoreCase( "Q" ) )
			{
	
				System.out.println( "\nQuit all Nodes." );
				try {
					monitor.quitAllNodes();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}

			} // if

			else if ( Option.equalsIgnoreCase( "S" ) )
			{
				int whichInstrumented = 1;
				int startingNumber = 0;
	
				System.out.print( "How Many? >>> " );
				Option = input.KeyboardReadString();
				System.out.println();
				try {
					intOption = new Integer (Option);
					System.out.print( "Starting Number >>> " );
					Option = input.KeyboardReadString();
					startingNumber = new Integer(Option);
					whichInstrumented = (int) intOption / 2;
					for (int idx = 0; idx < intOption; idx++) {
						Option = "";
						System.out.println ("Starting Node: " + ++nodesStarted);
						String command = "";
						if (idx == whichInstrumented) command = getCommand("InstrumentedNode.jar", zone, nodesStarted, mean, basePath, intOption, startingNumber);
						else command = getCommand("Node.jar", zone, nodesStarted, mean, basePath, intOption, startingNumber);
						if (runDistributed) {
							command = "ssh " + hydraNodes.get(idx % hydraNodes.size()) + " /apps/java/default/bin/" + command;
						}
						System.out.println(command);
						Runtime rt = Runtime.getRuntime();
						long stime = System.currentTimeMillis();
						rt.exec(command);
						monitor.writeMessageToFile("Started Node," + zone.getName() + nodesStarted + ", milliseconds," + (System.currentTimeMillis() - stime));
						Thread.sleep(1000);
					}
				}
				catch (Exception e) {
					System.out.println("ERROR!");
					e.printStackTrace();
				}

			} // if

			//////////// option X ////////////

			else if ( Option.equalsIgnoreCase( "X" ) )
			{
				Done = true;
				try {
					monitor.quitAllNodes();
					monitor.Halt();
				} catch (IOException e) {
					System.out.println("Halt Failed");
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}

			} // if

		} // while

		System.out.println( "\nConsole Stopped." );

	}

	private static String getCommand(String whatToRun, ZoneRelay zone, int nodesStarted,
			int mean, String basePath, int numberOfNodes, int startingNumber) {
		String command = "java -jar " + basePath + "/" + whatToRun 
			+ " " + zone.getName() + " " 
			+ zone.getDimension() + " "
			+ zone.getWindowSize() + " "
			+ (zone.getName() + (nodesStarted + startingNumber)) + " "
			+ basePath + " "
			+ mean+ " "
			+ numberOfNodes + " > " + basePath + "/" + (zone.getName() + (nodesStarted + startingNumber)) + ".log"
			+ " 2> " + basePath + "/" + (zone.getName() + (nodesStarted + startingNumber)) + ".err";
		return command;
	}

	private static void addRemoteZones(SimpleConfig config, ZoneRelay zone) {
		String remoteZones;
		remoteZones = config.getProperty("remoteZones").trim();
		if (remoteZones.length() > 0) {
			String[] remoteZoneData = remoteZones.split(",");
			for (int i = 0; i < remoteZoneData.length; i++) {
				String[] rZone = remoteZoneData[i].split(":");
				zone.addRemoteZone(rZone[0], rZone[1], new Integer(rZone[2]));
			}
		}
	}

	private static ArrayList<String> addRunNodes(SimpleConfig config) {
		ArrayList<String> theNodes = new ArrayList<String> ();
		String hNodes = config.getProperty("hydraNodes").trim();
		if (hNodes.length() > 0) {
			String[] hydraNodes = hNodes.split(",");
			for (int i = 0; i < hydraNodes.length; i++) {
				theNodes.add(hydraNodes[i]);
			}
		}
		return theNodes;
	}

	
	private static void printConsoleMenu() {

		System.out.println( "\n\n\n\n" );
		System.out.println( "---------------------------------------------------");
		System.out.println( "| Broadcast System Command Console:               |" );
		System.out.println( "|                                                 |" );
		System.out.println( "| C: Check Memory                                 |" );
		System.out.println( "| S: Start Nodes                                  |" );
		System.out.println( "| M: Simulate MedVac Request                      |" );
		System.out.println( "| Q: Stop Nodes                                   |" );
		System.out.println( "| X: Stop System                                  |" );
		System.out.println( "|                                                 |" );
		System.out.println( "---------------------------------------------------");
		System.out.println( "  Select an Option: >>>> " );

	}

}
